﻿namespace FFF.Test.Application.Repositories.CF
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Domain.Repositories;
    using Abp.EntityFrameworkCore;
    using Abp.ObjectMapping;
    using Abp.UI;
    using Ydm.Helper;
    using Ydm.Extensions;
    using Microsoft.EntityFrameworkCore;
    using AutoMapper.QueryableExtensions;
    using FFF.Test.DataAccess.Framework;
    using FFF.Test.Application.Repositories.CF;
    using FFF.Test.Entity.CF;
    using FFF.Test.Entity.CF.Dto;
    using FFF.Test.Entity.CF.View;
    using FFF.Test.Application.PublicService.AppService.TreeGrid;
    using Abp.Application.Services.Dto;
    using Newtonsoft.Json;

    /// <summary>
    /// 业务参数字典表(树)仓储
    /// </summary>
    public class CFBizOptionRepository :
        YdmAbpRepositoryBase<CFBizOptionEntity, Guid, CFBizOptionCreateInputDto, CFBizOptionUpdateInputDto, CFBizOptionDto, ViewCFBizOption, ViewCFBizOption>,
        ICFBizOptionRepository
    {
        private readonly IObjectMapper _objectMapper;

        /// <summary>
        /// Initializes a new instance of the <see cref="CFBizOptionRepository"/> class.
        /// 仓储构造方法
        /// </summary>
        /// <param name="dbContextProvider">对应数据库的对象</param>
        /// <param name="objectMapper">自动映射对象</param>
        public CFBizOptionRepository(
            IDbContextProvider<MyDbContext> dbContextProvider,
            IObjectMapper objectMapper
            )
            : base(dbContextProvider, objectMapper)
        {
            this._objectMapper = objectMapper;
        }

        /// <summary>
        ///  获取树形列表(框架生成)
        /// </summary>
        /// <param name="inDto">树形输入dto</param>
        /// <returns>获取树形列表输出dto</returns>
        public async Task<List<TreeGridOutDto>> GetTreeGirdAsync(TreeGridInDto inDto)
        {
            List<TreeGridOutDto> result = new List<TreeGridOutDto>();
            PagedInputDto pagedInputDto = new PagedInputDto()
            {
                PageSize = inDto.PageSize,
                PageIndex = inDto.PageIndex,
                Order = inDto.Order
            };

            if (!string.IsNullOrEmpty(inDto.Filter))
            {
                pagedInputDto.Filter = JsonConvert.DeserializeObject<PageFilterDto>(inDto.Filter);
            }

            var query = base.GetView().AsNoTracking();
            var views = await query.Where(x => x.ParentGUID == inDto.Id).GetPageAsync<ViewCFBizOption, ViewCFBizOption>(pagedInputDto);
            foreach (var view in views.DataList)
            {
                TreeGridOutDto dto = new TreeGridOutDto()
                {
                    Id = view.Id,
                    Pid = view.ParentGUID,
                    Code = view.FullCode,
                    Text = view.BizOptionName,
                    OrderCode = view.OrderCode
                };

                // 判断下是否为末级节点
                if (!query.AsNoTracking().Any(x => x.ParentGUID == view.Id))
                {
                    dto.State = "open";
                }

                result.Add(dto);
            }

            return result;
        }

        /// <summary>
        ///  获取所有的父级的id 以,分割(框架生成)
        /// </summary>
        /// <param name="id">父级id</param>
        /// <returns>父级的id以,分割</returns>
        public async Task<string> GetFatherIdsAsync(Guid id)
        {
            var query = base.GetAll().AsNoTracking();
            var entity = await base.GetAsync(id);
            var ids = query.Where(x => entity.FullCode.Contains(x.FullCode) && entity.FullCode != x.FullCode).Select(x => x.Id.ToString());
            return string.Join(',', ids);
        }

        /// <summary>
        /// 重写新增方法(树)(框架生成)
        /// </summary>
        /// <param name="input">新增输入dto</param>
        /// <returns>输出dto</returns>
        public override async Task<CFBizOptionDto> CreateByDtoAsync(CFBizOptionCreateInputDto input)
        {
            string fullCode = await this.GetFullCode(input.ParentGUID);
            input.FullCode = fullCode;

            return await base.CreateByDtoAsync(input);
        }

        /// <summary>
        /// 更新的dto(树)(框架生成)
        /// </summary>
        /// <param name="input">输入对象</param>
        /// <returns>展示的Dto</returns>
        public async override Task<CFBizOptionDto> UpdateByDtoAsync(CFBizOptionUpdateInputDto input)
        {
            // 判断根节点是否改变 找出之前父节点和当前的父节点对比
            var entity = await this.GetAsync(input.Id);

            // 改变了那么需要重新刷新数据
            if (entity.ParentGUID != input.ParentGUID)
            {
                string fullCode = await this.GetFullCode(input.ParentGUID);

                // 把自级节点的所有的fullcode都要替换掉
                var childEntitys = await this.GetAll().Where(x => x.FullCode.StartsWith(entity.FullCode)).ToListAsync();
                childEntitys.ForEach(x => x.FullCode = fullCode);
            }

            return await base.UpdateByDtoAsync(input);
        }

        /// <summary>
        /// 删除需要把子级节点全部删除(树)(框架生成)
        /// </summary>
        /// <param name="id">id</param>
        /// <returns>删除task</returns>
        public override async Task DeleteAsync(Guid id)
        {
            var entity = await base.GetAsync(id);
            await base.DeleteAsync(x => x.FullCode.StartsWith(entity.FullCode));
        }

        /// <summary>
        /// 获取fullcode通过父级guid(框架生成)
        /// </summary>
        /// <param name="parentGuid">父guid</param>
        /// <returns>fullcode</returns>
        private async Task<string> GetFullCode(Guid? parentGuid)
        {
            var parentFullCode = parentGuid == null ? string.Empty : (await base.GetAsync(parentGuid.Value)).FullCode + ".";

            // 找到新的父级下面最大节点加1
            var query = base.GetAll().AsNoTracking().Where(x => x.ParentGUID == parentGuid);

            var maxFullCode = await query.MaxAsync(x => x.FullCode);

            // 去掉父级的节点
            var removeParentCode = maxFullCode == null ? "0" : maxFullCode.Remove(0, parentFullCode.Length);

            // 构造 001 002 这种格式的编码
            int.TryParse(removeParentCode, out var maxCount);

            string code = (maxCount + 1).ToString().PadLeft(3, '0');
            return parentFullCode + code;
        }
    }
}
